
def beforeTest():
    print "Before TEST"
    
def afterTest(retval, exc):
    print 'After TEST',
    if exc:
        print 'with exception %s(%s)' % (exc.__class__, exc)
    else:
        print 'with return value', retval

def aroundTest(method, *args, **kwargs):
    ret = method(*args,**kwargs)
    print "around Test", args
    return ret
    
def before():
    print "Before"
    
def after(retval, exc):
    print 'After',
    if exc:
        print 'with exception %s(%s)' % (exc.__class__, exc)
    else:
        print 'with return value', retval

def around(method, *args, **kwargs):
    method(*args,**kwargs)
    print "around", args

def weave(method, *args, **kwargs):
    
    if method.__name__ == "test":
        advice_before = beforeTest
        advice_after = afterTest
        advice_around = aroundTest
    else:
        advice_before = before
        advice_after = after
        advice_around = around

    def invoke_advice(*args, **kwargs):
        advice_before()
        try:
            if advice_around ==None:
                retval = method(*args, **kwargs)
            else:
                retval = advice_around(method, *args, **kwargs)
        except Exception, e:
            advice_after(None, e)
            raise
        else:
            advice_after(retval, None)
            return retval

    # Replace the method with our weaved one.
    try:
        class_ = method.im_class
    except:
        # The method is actually a simple function, wrap it in its namespace;
        method.func_globals[method.func_name] = invoke_advice
    else:
        #name = method.__name__
        setattr(class_, method.__name__, invoke_advice)
    return invoke_advice



@weave
def test(num):
    print "I am a test"
    return num

@weave
def fun():
    print "fun"
    
if __name__ == "__main__":
    test(8)
    fun()